/**
 * select
 * @author Brant Liu <br> 邮箱：<br>lbf1988@qq.com <br>日期：<br>2018/11/9
 * @version 1.0.0
 */
;!function (window) {
    "use strict";

    var isLucky = window.lucky && lucky.define, $, win, ready = {
        getPath: function(){
            var jsPath = document.currentScript ? document.currentScript.src : function(){
                var js = document.scripts
                    ,last = js.length - 1
                    ,src;
                for(var i = last; i > 0; i--){
                    if(js[i].readyState === 'interactive'){
                        src = js[i].src;
                        break;
                    }
                }
                return src || js[last].src;
            }();
            return jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
        }(),

        //获取节点的style属性值
        getStyle: function(node, name){
            var style = node.currentStyle ? node.currentStyle : window.getComputedStyle(node, null);
            return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name);
        },

        //载入CSS配件
        link: function(href, fn, cssname){
            //未设置路径，则不主动加载css
            if(!select.path) return;

            var head = document.getElementsByTagName("head")[0], link = document.createElement('link');
            if(typeof fn === 'string') cssname = fn;
            var app = (cssname || href).replace(/\.|\//g, '');
            var id = 'selectcss-'+ app, timeout = 0;

            link.rel = 'stylesheet';
            link.href = select.path + href;
            link.id = id;

            if(!document.getElementById(id)){
                head.appendChild(link);
            }

            if(typeof fn !== 'function') return;

            //轮询css是否加载完毕
            (function poll() {
                if(++timeout > 8 * 1000 / 100){
                    return window.console && console.error('select.css: Invalid');
                };
                parseInt(ready.getStyle(document.getElementById(id), 'width')) === 1989 ? fn() : setTimeout(poll, 100);
            }());
        }
    };

    var thisSelect = function(){
        var that = this, options = that.config;
        return {
            element: that.element,
            originalSelect: that.select,
            config: options,
            setVal: function(val){
                that.setSelectValue.call(that,val,that.getValueByElementIdOrValue(val,true));
            },
            show: function(){
                that.showDropdown.call(that);
            },
            hide: function(){
                that.closeDropdown.call(that);
            },
            toggle: function(){
                that.toggleDropdown.call(that);
            },
            setDisabled: function(changeStatus){
                that.setDisabledStatus.call(that, changeStatus);
            },
            on: function(eventName, callback){
                that.on.call(that, eventName, callback);
            }
        }
    };

    var select = {
        MOD_NAME:"select",
        path: ready.getPath,
        ready: function (callback) {
            var cssname = 'select' ,path = (isLucky ? 'forms/select/' : 'theme/') + 'select.css?v='+ new Date().getTime();
            isLucky ? lucky.addcss(path, callback, cssname) : ready.link(path, callback, cssname);
            return this;
        }
    };

    var ClassSelect = function (element, options) {
        this.element = element;
        this.config = $.extend({}, this.config, options);
        this.listeners = {};
        this.render();
    };

    var doms = {
        //Select组件最外层容器
        selectContainer: "lucky-select",
        //Select展开
        selectContainerOpen: "lucky-select-container--open",
        //Select禁用
        selectContainerDisabled: "lucky-select-container--disabled",
        //在下面显示
        selectBelow:["lucky-select-container--below", "lucky-select-dropdown--below"],
        //在上面显示
        selectAbove:["lucky-select-container--above", "lucky-select-dropdown--above"],
        //搜索容器
        selectSearchContainer: "lucky-select-search",
        selectSearchInput:"lucky-select-search__field",
        selectSelection: "lucky-select-selection",
        selectSelectionTextContainer: "lucky-select-selection__rendered",
        selectDropdown: "lucky-select-dropdown",
        selectDropdownContainer: "lucky-select-results",
        selectDropdownRoot: "lucky-select-results__options",
        selectDropdownOption: "lucky-select-results__option",
        selectDropdownOptionHighlighted: "lucky-select-results__option--highlighted",
        selectHiddenClass: "lucky-select-hidden"
    };

    var events = {
        open:"open", close: "close", change: "change"
    };

    ClassSelect.prototype.config = {
        placeholder: "请选择",
        search: false,
        multiple: false,
        disabled: false,
        ajax:false,
        emptyItemMessage:"没有选项",
        /**
         * [{
         *      icon: "",
         *      text: "",
         *      value: "",
         *      selected: boolean,
         *      disabled: boolean,
         *      children:[{icon: "",text: "",value: "",selected: boolean,disabled: boolean}]
         * }]
         * */
        data:[]
    };

    //初始化自定义Select组件
    ClassSelect.prototype.render = function(){
        var that = this;
        //读取原Select配置组件属性
        that.readAttributeInitConfig();

        //禁用原Select组件
        that.setOriginalStatus();

        //如果已经渲染，则删除
        that.isRender() && that.getSelectElement().remove();

        //创建
        that.createSelect(function (selectElem) {
            that.element.after(selectElem);
            that.select = selectElem;
            that.setSelectWidth();
            var callParams = {select:that.select,element: that.element};
            //渲染成功后执行
            that.config.render && that.config.render(callParams);
            that.parseData();
            that.events();
            $(window).on('resize', function(){
                that.setSelectWidth();
                if(that.isOpen()){
                    that.autoSelectOffset();
                }
            });
        });
    };

    //读取组件元素配置项
    ClassSelect.prototype.readAttributeInitConfig = function () {
        var that = this;
        //读取 select placeholder
        that.config.placeholder = (function(){
            var optionFirst = $(that.element[0].options[0]);
            if(optionFirst.length > 0 && $.trim(optionFirst.val()).length === 0){
                return optionFirst.text();
            }
            return that.element.attr("placeholder") ? that.element.attr("placeholder"):that.config.placeholder;
        }());
        that.config.disabled = that.element.attr("disabled") ? true : that.config.disabled;
        that.config.multiple = that.element.attr("multiple") ? true : that.config.multiple;

        that.config.search = that.element.attr("lucky-search") !== undefined ? true : that.config.search;
    };

    //原Select是否禁用
    ClassSelect.prototype.originalStatus = function(){
        return this.element.hasClass("." + doms.selectHiddenClass);
    };

    //禁用原Select组件
    ClassSelect.prototype.setOriginalStatus = function(){
        if(!this.originalStatus()){
            this.element.addClass(doms.selectHiddenClass);
        }
    };

    //获取Select组件
    ClassSelect.prototype.getSelectElement = function () {
        return this.element.next("." + doms.selectContainer);
    };

    ClassSelect.prototype.getSelectedElement = function(){
        return this.select.find("." + doms.selectDropdownOption + "[aria-selected='true']");
    };

    //检查是否已经渲染
    ClassSelect.prototype.isRender = function () {
        return this.getSelectElement()[0] ? true : false;
    };

    ClassSelect.prototype.getSelectValue = function(){
        return this.element.find("option:selected").val();
    };

    ClassSelect.prototype.setSelectValue = function(value, selectedValue){
        var that = this,
            selectTextElem = that.select.find("." + doms.selectSelectionTextContainer),
            selectRootElem = that.select.find("." + doms.selectDropdownRoot);
        if(selectedValue){
            var text = selectedValue.icon ? ("<i class='"+ selectedValue.icon +"'></i>" + selectedValue.text) : selectedValue.text,
                optionElem = selectRootElem.find("#" + selectedValue.id);
            selectRootElem.find("li[role='item']").each(function(){
                var option = $(this);
                if(option.attr("aria-disabled"))return;
                option.attr("aria-selected",false);
            });
            optionElem.attr("aria-selected",true);
            that.setSelectedScroll(optionElem);
            selectTextElem.html(text);
        }
        this.element.val(value);
    };

    ClassSelect.prototype.setSelectedScroll = function(selected){
        var selectRootElem = this.select.find("." + doms.selectDropdownRoot);
        if(!selected[0]) return;
        var posTop = selected.position().top
            ,containerHeight = selectRootElem.height()
            ,optionHeight = selected.height();
        if(posTop > containerHeight){
            selectRootElem.scrollTop(posTop + selectRootElem.scrollTop() - containerHeight + optionHeight);
        }
        if(posTop < 0){
            selectRootElem.scrollTop(posTop + selectRootElem.scrollTop() - optionHeight - optionHeight);
        }
    };

    //获取原Select的宽度
    ClassSelect.prototype.getSelectWidth = function(){
        return this.element.parent().outerWidth();
    };

    //设置自定义Select宽度
    ClassSelect.prototype.setSelectWidth = function(){
        this.select.width(this.getSelectWidth());
    };

    //根据ElementId获取对应的值
    ClassSelect.prototype.getValueByElementIdOrValue = function(elementId, isValue){
        var that = this, data = that.config.data, targetObj = {};
        if(that.isDisabled()) return targetObj;
        if(!data && data.length === 0){
            return targetObj;
        }
        function valueValid(item){
            if(isValue){
                if(item.value === elementId){
                    return true;
                }
            }else{
                if(item.id === elementId){
                    return true;
                }
            }
            return false;
        }
        for(var i=0,len=data.length; i < len; i++){
            var item = data[i];
            if(item.children && item.children.length > 0){
                var childrens = item.children;
                for(var j=0,len2=childrens.length; j<len2; j++){
                    var child = childrens[j];
                    if(valueValid(child)){
                        targetObj = child;
                        break;
                    }
                }
            }else{
                if(valueValid(item)){
                    targetObj = item;
                    break;
                }
            }
        }
        return targetObj;
    };

    //创建容器
    ClassSelect.prototype.createSelect = function (callback) {
        var that = this, config = that.config,
            elementId = config.id = config.id ? config.id : that.generateId();

        var selectElem = $([
            '<div id="'+ elementId +'" class="lucky-select lucky-select-container lucky-select-container--default lucky-select-container--below ' + (config.disabled ? doms.selectContainerDisabled:'') + '">'
                ,'<div class="selection">'
                    ,'<div class="lucky-select-selection '+ (config.multiple ? "lucky-select-selection--multiple":"lucky-select-selection--single") +'" role="combobox" tabindex="0" aria-haspopup="true" aria-expanded="false">'
                        ,'<span class="lucky-select-selection__rendered">' + config.placeholder + '</span>'
                        ,'<span class="lucky-select-selection__arrow" role="presentation"><b role="presentation"></b></span>'
                    ,'</div>'
                ,'</div>'
                ,'<div class="lucky-select-dropdown lucky-select-dropdown--below">'
                , config.search ? (function(){
                    return "<div class=\"lucky-select-search lucky-select-search--dropdown\"><input class=\"lucky-select-search__field\" type=\"search\" /></div>";
                  }()) : ''
                    , '<div class="lucky-select-results"></div>'
                ,'</div>'
            ,'</div>'
        ].join(''));

        callback(selectElem);
    };

    //是否禁用
    ClassSelect.prototype.isDisabled = function(){
        return this.config.disabled;
    };

    ClassSelect.prototype.setDisabledStatus = function(changeStatus){
        if(changeStatus){
            this.config.disabled = true;
            this.select.addClass(doms.selectContainerDisabled);
            this.element[0].disabled = true;
        }else{
            this.config.disabled = false;
            this.select.removeClass(doms.selectContainerDisabled);
            this.element[0].disabled = false;
        }
    };

    //获取Select搜索框
    ClassSelect.prototype.getSearchElement = function(){
        return this.config.search ? this.select.find("." + doms.selectSearchInput) : null;
    };

    //重置Select搜索框
    ClassSelect.prototype.setSearchInputValueEmpty = function(){
        var searchInput = this.getSearchElement();
        if(searchInput){
            searchInput.val("");
        }
    };

    //读取原Select的选择项
    ClassSelect.prototype.readOptions = function(){
        var that = this, element = that.element;
        var optionData = function(options){
            var arr = [], recordValue = [];
            options.each(function(index, item){
                var $option = $(this);
                if (!$option.is('option') && !$option.is('optgroup')) {
                    return;
                }
                if($option.is('option') && $.inArray($option.val(), recordValue) == -1){
                    var optionItem = that.readOptionItem($option);
                    arr.push(optionItem);
                    recordValue.push(optionItem.value);
                }else if($option.is('optgroup')){
                    var item = {text: item.label, children:[]};
                    $option.find("*").each(function(){
                        var $child = $(this), optionItem = that.readOptionItem($child);
                        item.children.push(optionItem);
                        recordValue.push(optionItem.value);
                    });
                    arr.push(item);
                }
            });
            return arr;
        }(element.find("*"));
        return optionData;
    };

    ClassSelect.prototype.readOptionItem = function(option){
        return {
            id:this.generateId(),
            icon: option.attr("lucky-icon"),
            text: option.text(),
            value: option.val(),
            selected: option.prop("selected"),
            disabled: option.prop("disabled")
        };
    };

    ClassSelect.prototype.generateId = function(){
        var that = this, element = that.element;
        var id = '';
        if (element.attr('id') != null) {
            id = element.attr('id') + '-' + that.generateChars(8);
        } else if (element.attr('name') != null) {
            id = element.attr('name') + '-' + that.generateChars(8);
        } else {
            id = that.generateChars(8);
        }
        id = id.replace(/(:|\.|\[|\]|,)/g, '');
        id = 'lucky-select-' + id;
        return id;
    };

    ClassSelect.prototype.generateChars = function(length){
        var chars = '';
        for (var i = 0; i < length; i++) {
            var randomChar = Math.floor(Math.random() * 36);
            chars += randomChar.toString(36);
        }
        return chars;
    };

    //初始化数据
    ClassSelect.prototype.parseData = function(){
        var that = this,
            element = that.element,
            config = that.config;
        if(config.ajax){
            //Ajax数据
        }else{
            //Select数据
            if(config.data.length === 0){
                config.data = that.readOptions();
            }
            that.useTemplate(config.data);
        }
    };

    //构建模板并且初始化选择项
    ClassSelect.prototype.useTemplate = function(data, callback){
        var that = this;

        if(data.length === 0){
            that.setSelectOptions(that.getEmptyOptions());
            return;
        }

        var defaultValueHandler = function(item){
            return [
                '<li class="lucky-select-results__option" role="item" id="'+ item.id +'" value="' + (item.value ? item.value : '') + '"  '+ (item.disabled ? (' '+"aria-disabled=\"true\"") : '') +' '+ (item.disabled === false ? ("aria-selected=\""+ (item.selected ? "true":"false" ) +"\""):"") +'  >',
                (function(){
                    return item.icon ? ("<i class='"+ item.icon +"'></i>") : "";
                }()),
                item.text,
                '</li>'
            ].join('');
        };

        var templateParse = (function(items){
            var arr = [];
            arr.push("<ul class=\"lucky-select-results__options\">");
            for(var i=0, len=items.length; i<len;i++){
                var item = items[i];
                if(item.children && item.children.length > 0){
                    arr.push("<li class=\"lucky-select-results__option\" role=\"group\">");
                        arr.push('<strong class="lucky-select-results__group">' + item.text + '</strong>');
                        arr.push('<ul class="lucky-select-results__options lucky-select-results__options--nested">');
                        for(var j=0, len2=item.children.length; j < len2; j++){
                            var childItem = item.children[j];
                            arr.push(defaultValueHandler(childItem));
                        }
                        arr.push('</ul>');
                    arr.push("</li>")
                }else{
                    arr.push(defaultValueHandler(item));
                }
            }
            arr.push("</ul>");
            return arr.join('');
        }(data));

        that.setSelectOptions(templateParse);
        var defaultSelectedValue = that.getSelectValue();
        if(defaultSelectedValue !== undefined){
            that.setSelectValue(defaultSelectedValue, that.getValueByElementIdOrValue(defaultSelectedValue,true));
        }
        if(callback && typeof callback === "function"){
            callback();
        }
    };

    ClassSelect.prototype.getEmptyOptions = function(){
        return [
            '<ul class="lucky-select-results__options">'
                ,'<li class="lucky-select-results__option lucky-select-results__message">' + this.config.emptyItemMessage + '</li>'
            ,'</ul>'
        ].join('');
    };

    ClassSelect.prototype.setSelectOptions = function(optionsHtml){
        var that = this,
            selectDropdownContainer = that.select.find("." + doms.selectDropdownContainer);
        selectDropdownContainer.empty();
        selectDropdownContainer.html(optionsHtml);
    };

    //查询数据
    ClassSelect.prototype.onSearchData = function(val){
        var that = this, data = that.config.data, arr = [], val = val.toLowerCase();
        for(var i=0,len=data.length;i<len;i++){
            var item = data[i], children = item.children;
            if(children && children.length >0){
                var itemChildren = [];
                for(var j=0,len2=children.length;j<len2;j++){
                    var child = children[j];
                    if(child.text.toLowerCase().indexOf(val) > -1){
                        itemChildren.push(child);
                    }
                }
                if(itemChildren.length > 0){
                    arr.push({text: item.text, children: itemChildren});
                }
            }else{
                if(item.text.toLowerCase().indexOf(val) > -1){
                    arr.push(item);
                }
            }
        }
        that.useTemplate(arr, function () {
            //绑定选项hover click事件 keydown事件
            that.bindSelectOptionsEvent();
        });
    };

    //自适应上下定位识别
    ClassSelect.prototype.autoSelectOffset = function(){
        var that = this,
            top = that.select.offset().top + that.select.outerHeight() + 5 - win.scrollTop(),
            selectDropdown = that.select.find("." + doms.selectDropdown),
            selectDropdownHeight = selectDropdown.outerHeight();

        that.removeSelectOffset();

        if(top + selectDropdownHeight > win.height() && top >= selectDropdownHeight){
            selectDropdown.addClass(doms.selectAbove[1]).css("top",(selectDropdownHeight) * -1);
            that.select.addClass(doms.selectAbove[0]);
        }else{
            selectDropdown.addClass(doms.selectBelow[1]).css("top",that.select.outerHeight());
            that.select.addClass(doms.selectBelow[0]);
        }
    };

    //删除自适应上下定位识别
    ClassSelect.prototype.removeSelectOffset = function(){
        this.select.removeClass(doms.selectBelow[0] + " " + doms.selectAbove[0]);
        this.select.find("." + doms.selectDropdown).removeClass(doms.selectBelow[1] + " " + doms.selectAbove[1]);
    };

    //是否是展开状态
    ClassSelect.prototype.isOpen = function(){
        return this.select.hasClass(doms.selectContainerOpen);
    };

    //展开选择项
    ClassSelect.prototype.showDropdown = function(){
        if(!this.isOpen() && !this.isDisabled()){
            this.autoSelectOffset();
            if(this.config.search){
                this.getSearchElement() && this.getSearchElement().focus();
            }
            this.setSelectedScroll(this.getSelectedElement());
            this.trigger(events.open,{
                elem: this.element
            });
            this.select.addClass(doms.selectContainerOpen);
        }
    };

    //关闭选择项
    ClassSelect.prototype.closeDropdown = function(){
        if(this.isOpen()){
            this.select.removeClass(doms.selectContainerOpen);
            this.trigger(events.close,{
                elem: this.element
            });
            this.removeSelectOffset();
            if(this.config.search && this.getSearchElement()){
                if(this.getSearchElement().val().length > 0){
                    this.useTemplate(this.config.data);
                }
            }
            this.setSearchInputValueEmpty();
        }
    };

    //切换下拉展开隐藏
    ClassSelect.prototype.toggleDropdown = function () {
        var that = this;
        if(that.isDisabled()) return;
        if(!that.isOpen()){
            that.showDropdown();
        }else{
            that.closeDropdown();
        }
    };

    //注册事件
    ClassSelect.prototype.on = function(eventName, callback){
        var that = this;
        if(eventName in that.listeners){
            that.listeners[eventName].push(callback);
        } else {
            that.listeners[eventName] = [callback];
        }
    };

    //触发注册的事件
    ClassSelect.prototype.trigger = function(eventName, params){
        var listeners = this.listeners[eventName];
        if(listeners === undefined){
            return;
        }
        for(var i = 0, len = listeners.length; i<len;i++){
            listeners[i].apply(this, [params]);
        }
    };

    //绑定hover 选项点击事件
    ClassSelect.prototype.bindSelectOptionsEvent = function(){
        var that = this;
        if(that.isDisabled()) return;

        //选项hover事件
        that.select.find("." + doms.selectDropdownOption).hover(function () {
            $(this).addClass(doms.selectDropdownOptionHighlighted);
        },function () {
            $(this).removeClass(doms.selectDropdownOptionHighlighted);
        });

        //选项点击事件
        that.select.find("." + doms.selectDropdownOption + "[role='item']").on("click", function(){
            var othis = $(this),
                id = othis.attr("id"),
                disabled = othis.attr("aria-disabled");

            if(disabled) return false;

            var selected = that.getValueByElementIdOrValue(id,false);
            that.setSelectValue(selected.value, selected);
            //触发改变事件
            that.trigger(events.change,{
                elem: that.element,
                value:selected.value,
                option:selected
            });
            that.closeDropdown();
        });

        that.select.find("." + doms.selectSelection + ",." + doms.selectSearchInput).on("keydown",function(event){
            var keyCode = event.keyCode, options = that.select.find("." + doms.selectDropdownOption + "[role='item']");
            //Tab键隐藏
            if(keyCode === 9){
                that.closeDropdown();
            }
            var optionsItems = function(){
                var arrIds = [];
                options.each(function(){
                    if($(this).attr("aria-disabled")){
                        return;
                    }
                    arrIds.push($(this).attr("id"));
                });
                return arrIds;
            }();
            var setThisSelectOption = function(prevNext){
                event.preventDefault();
                var thisHighIndex, optionHighlightedElem;
                //高亮状态 没有的话默认选择项
                optionHighlightedElem = that.select.find("." + doms.selectDropdownOptionHighlighted);
                if(optionHighlightedElem[0]){
                    thisHighIndex = $.inArray(optionHighlightedElem.attr("id"), optionsItems);
                }else{
                    var thisSelectedId = that.getSelectedElement().attr("id");
                    thisHighIndex = $.inArray(thisSelectedId, optionsItems);
                }
                var indexExpression = thisHighIndex + (prevNext === "prev" ? -1 : 1);
                if(indexExpression === -1 || (indexExpression === optionsItems.length)){
                    return;
                }
                var nearbyElem = that.select.find("#" + optionsItems[indexExpression]);
                options.removeClass(doms.selectDropdownOptionHighlighted);
                nearbyElem.addClass(doms.selectDropdownOptionHighlighted);
                //设置位置后，需要定位滚动条
                that.setSelectedScroll(nearbyElem);
            };
            if(keyCode === 38) setThisSelectOption('prev'); //Up 键
            if(keyCode === 40) setThisSelectOption('next'); //Down 键
            //Enter 键
            if(keyCode === 13){
                event.preventDefault();
                options.each(function(){
                    if($(this).hasClass(doms.selectDropdownOptionHighlighted)){
                        $(this).trigger('click');
                        return;
                    }
                });
            }
        }).on("keyup", function(event){
            var keyCode = event.keyCode;
            //Tab键展开
            if(keyCode === 9){
                that.showDropdown();
            }
        });
    };

    //初始化事件
    ClassSelect.prototype.events = function(){
        var that = this;
        if(that.isDisabled()) return;

        that.select.find("." + doms.selectSelection).on("click", function(event){
            event.preventDefault();
            that.toggleDropdown();
        });

        //绑定选项hover click事件 keydown事件
        that.bindSelectOptionsEvent();

        //搜索
        if(that.config.search && that.getSearchElement()){
            that.getSearchElement().on("keyup",function(e){
                e.preventDefault();
                var keyCode = e.keyCode;
                if(keyCode === 9 || keyCode === 13
                    || keyCode === 37 || keyCode === 38
                    || keyCode === 39 || keyCode === 40
                ){
                    return false;
                }
                var $this = $(this), searchValue = $this.val();
                that.onSearchData(searchValue);
            });
        }

        var clickOtherClose = function(e){
            if(!$(e.target).parent().hasClass(doms.selectSelection)
                    && !$(e.target).parents().hasClass(doms.selectDropdown)){
                that.closeDropdown();
            }
        };

        $(document).off('click', clickOtherClose).on('click', clickOtherClose);
    };

    ready.run = function ($$) {
        $ = $$;
        win = $(window);
        select.render = function(element, options){
            var $element = $(element);
            if(!$element[0]) return;
            var inst = new ClassSelect($element, options);
            return thisSelect.call(inst);
        };
    };

    window.lucky && lucky.define ? (
        select.ready(), lucky.define(['jquery'], function(exports){
            select.path = lucky.cache.dir;
            ready.run(window.jQuery);

            window.select = select;
            exports(select.MOD_NAME, select);
        })
    ) : (
        (typeof define === 'function' && define.amd) ? define(['jquery'], function(){
            //requirejs加载
            ready.run(window.jQuery);
            return select;
        }) : function(){
            //普通script标签加载
            ready.run(window.jQuery);
            select.ready();
        }()
    );
}(window);